// =====================================================================================
// 
//       Filename:  raster.h
// 
//    Description:  Définition d'une table de données raster
// 
//        Version:  1.0
//        Created:  24/07/2009 00:07:59
//       Revision:  none
//       Compiler:  g++
// 
//         Author:  François Hissel (fh), francois.hissel@m4x.org
//        Company:  
// 
// =====================================================================================


#ifndef  RASTER_H_INC
#define  RASTER_H_INC

#include	<string>
#include	<exception>
#include	<iostream>

using namespace std;

/**
 * \class RasterException
 * \brief Exception soulevée lorsqu'une erreur survient pendant une opération sur une carte raster
 *
 * La classe permet de gérer les erreurs survenant pendant des opérations sur des cartes raster.
 */
class RasterException:public exception {
	public:
		/**
		 * \brief Ensemble des codes d'erreur possibles
		 *
		 * L'énumération rassemble les codes d'erreur qui peuvent être retournés lorsqu'une opération sur une classe Raster a généré une erreur.
		 */
		enum Code {BAD_INDEX,	//!< Indice incorrect
			BAD_DEFINITION	//!< Définition des paramètres de la carte raster incorrecte
			} code;	//!< Code de l'erreur
		string message;	//!< Message décrivant l'erreur
		RasterException(Code pcode):code(pcode) {}	//!< Constructeur d'exception sans message de sortie
		RasterException(Code pcode,string pmessage):code(pcode),message(pmessage) {}	//!< Constructeur d'exception avec message de sortie
		~RasterException() throw() {}	//!< Destructeur standard
		const char* what() const throw();	//!< Retourne un message descriptif de l'exception
};

/**
 * \struct RGB
 * \brief Description d'une couleur au format RGB
 */
struct RGB {
	double r;	//!< Quantité de rouge (comprise entre 0 et 1);
	double g;	//!< Quantité de vert (comprise entre 0 et 1);
	double b;	//!< Quantité de bleu (comprise entre 0 et 1);
	RGB() {}	//!< Constructeur standard sans initialisation des membres
	RGB(double pr,double pg,double pb):r(pr),g(pg),b(pb) {}	//!< Constructeur standard avec initialisation des membres

	/**
	 * \brief Retourne une couleur à partir d'une échelle
	 *
	 * La fonction prend en argument un nombre flottant compris entre 0 et 1 et renvoie une couleur correspondant à ce nombre choisie dans une échelle rouge-orange-jaune-blanc.
	 * \param valeur Valeur entre 0 et 1 à convertir en couleur
	 */
	static RGB couleur(double valeur);

	/**
	 * \brief Retourne une couleur à partir de son indice dans une palette prédéfinie
	 *
	 * La fonction prend en argument un nombre entier positif qui représente l'indice de la couleur à choisir dans la palette. La correspondance entre les indices et les couleurs est la suivante :
	 * 	- 0 : noir
	 * 	- 1 : bleu
	 * 	- 2 : vert
	 * 	- 3 : cyan
	 * 	- 4 : rouge
	 * 	- 5 : magenta
	 * 	- 6 : orange
	 * 	- 7 : gris foncé
	 * 	- 8 : gris clair
	 * 	- 9 : bleu clair
	 * 	- 10 : vert clair
	 * 	- 11 : cyan clair
	 * 	- 12 : rose
	 * 	- 13 : magenta clair
	 * 	- 14 : jaune
	 * 	- 15 : blanc
	 * \param num Indice de la couleur à renvoyer
	 */
	static RGB palette(unsigned char num);

	/**
	 * \brief Convertit une couleur RGB en un nombre entier de 4 octets sous la forme 0xAARRGGBB
	 *
	 * La fonction retourne un nombre entier représentant la couleur de l'instance. L'octet de poids fort correspond à la valeur de la transparence, puis les octets suivants représentent respectivement le rouge, le vert et le bleu.
	 * \return Valeur entière représentant la couleur
	 */
	int to_int() const;
};

/**
 * \class Raster
 * \brief Type de base pour la description d'une carte raster.
 *
 * La classe représente un type de base pour la description d'une carte raster. Il s'agit d'une classe abstraite dont héritent les différents types de cartes raster (discrètes, continues).
 */
class Raster {
	public:
		/**
		 * \enum Type
		 * \brief Définition des types de données que peut contenir une carte raster
		 *
		 * L'énumération définit les différents types de données possibles que peut contenir une carte raster. Chaque carte contient un type de données, représenté par le paramètre type
		 */
		enum Type {
			CONTINU,	//!< Type de données continues
			DISCRET	//!< Type de données discrètes
		};

		/**
		 * \brief Constructeur standard
		 *
		 * Le constructeur initialise tous les champs de la classe. Ceux-ci sont obligatoires pour définir le format de la structure et notamment les fonctions d'exportation
		 * \param ptype Type de données contenues dans la carte raster
		 * \param ptaillex Nombre de cellules en abscisse
		 * \param ptailley Nombre de cellules en ordonnée
		 * \param pxmin Abscisse minimale de la carte
		 * \param pymin Ordonnée minimale de la carte
		 * \param pcellule Taille des cellules
		 */
		Raster(Type ptype,int ptaillex,int ptailley,double pxmin,double pymin,double pcellule);
		virtual ~Raster() {}	//!< Destructeur standard

		/**
		 * \brief Retourne le type de la carte raster
		 *
		 * La fonction retourne le type (continu ou discret) de la carte raster courante. Elle est utilisée pour connaître la méthode de représentation des données.
		 * \return Type de la carte raster
		 */
		Type type() {return _type;}
		int taillex() const {return _taillex;}	//!< Accès à la taille du tableau selon la première composante
		int tailley() const {return _tailley;}	//!< Accès à la taille du tableau selon la seconde composante
		double xmin() const {return _xmin;}	//!< Accès à l'abscisse minimale de la carte
		double ymin() const {return _ymin;}	//!< Accès à l'ordonnée minimale de la carte
		double cellule() const {return _cellule;}	//!< Accès à la taille des cellules

		/**
		 * \brief Retourne la couleur du pixel dont les coordonnées sont mentionnées
		 *
		 * La fonction calcule et retourne la couleur que doit avoir le pixel spécifié en argument.
		 * \param i Abscisse du pixel dans la structure de données
		 * \param j Ordonnée du pixel dans la structure de données
		 * \return Couleur du pixel
		 */
		virtual RGB couleur(int i,int j) const=0;

		/**
		 * \brief Exportation de la carte au format ArcInfo ASCII
		 *
		 * La méthode exporte la carte dans un fichier au format ASCII ArcInfo spécifié par le paramètre fichier
		 * \param fichier Nom du fichier à exporter
		 */
		void exporte(string fichier) const;
	protected:
		Raster() {}	//!< Constructeur standard, sans initialisation des données
		Type _type;	//!< Indique le type des données représentées sur la carte raster. Selon le type, la représentation cartographique diffère. Pour des données continues, les couleurs sont choisies sur une palette continue. Pour des données discrètes, elles sont choisies aléatoirement parmi des couleurs claires.
		int _taillex;	//!< Taille du tableau selon la première composante
		int _tailley;	//!< Taille du tableau selon la deuxième composante
		double _xmin;	//!< Abscisse minimale de la carte
		double _ymin;	//!< Ordonnée minimale de la carte
		double _cellule;	//!< Taille des cellules
		double _novalue;	//!< Valeur qui indique l'absence de données (cela est inclus dans la spécification des fichiers ASCII ArcInfo

		/**
		 * \brief Affiche la donnée de composante (i,j) sur un flux de sortie
		 *
		 * La fonction virtuelle pure affiche la donnée de composante (i,j) contenue dans la structure sur le flux de sortie out spécifié en argument. Elle sert à l'export de la carte dans un fichier.
		 * \param i Première composante de la donnée à afficher
		 * \param j Seconde composante de la donnée à afficher
		 * \param out Flux de sortie de destination
		 */
		virtual void affiche(int i,int j,ostream &out) const=0;
};

/**
 * \class RasterContinu
 * \brief Structure de données permettant la représentation d'une carte raster à données dans un espace continu
 *
 * La classe, héritée de la classe Raster, permet le stockage d'une carte raster dont les données sont continues.
 */
class RasterContinu:public Raster {
	public:
		double min;	//!< Valeur de la donnée correspondant au début de la palette des couleurs pour l'affichage
		double max;	//!< Valeur de la donnée correspondant à la fin de la palette des couleurs pour l'affichage

		/**
		 * \brief Constructeur standard
		 *
		 * Le constructeur initialise tous les champs de la classe. Ceux-ci sont obligatoires pour définir le format de la structure et notamment les fonctions d'exportation
		 * \param ptaillex Nombre de cellules en abscisse
		 * \param ptailley Nombre de cellules en ordonnée
		 * \param pxmin Abscisse minimale de la carte
		 * \param pymin Ordonnée minimale de la carte
		 * \param pcellule Taille des cellules
		 * \param pmin Valeur minimale des données affichées, la palette des couleurs est étirée entre pmin et pmax
		 * \param pmax Valeur maximale des données affichées, la palette des couleurs est étirée entre pmin et pmax
		 */
		RasterContinu(int ptaillex,int ptailley,double pxmin,double pymin,double pcellule,double pmin,double pmax);

		/**
		 * \brief Constructeur d'un raster à partir d'un fichier
		 *
		 * Le constructeur lit tous les champs et les données de la carte raster à partir du fichier spécifié en argument.
		 * \param fichier Nom du fichier à importer
		 */
		RasterContinu(string fichier):Raster(CONTINU,0,0,0,0,0) {importe(fichier);}

		/**
		 * \brief Constructeur d'un raster à partir d'un fichier dont seule une partie sera importée
		 *
		 * Le constructeur lit uniquement les champs de données de la carte raster qui sont compris dans les frontières définies, à partir du fichier spécifié en argument.
		 * \param fichier Nom du fichier à importer
		 * \param pxmin Abscisse minimale de la zone à importer
		 * \param pymin Ordonnée minimale de la zone à importer
		 * \param pxmax Abscisse maximale de la zone à importer
		 * \param pymax Ordonnée maximale de la zone à importer
		 */
		RasterContinu(string fichier,double pxmin,double pymin,double pxmax,double pymax):Raster(CONTINU,0,0,0,0,0) {importe(fichier,pxmin,pymin,pxmax,pymax);}

		virtual ~RasterContinu();	//!< Destructeur standard, libère les ressources associées
		double& operator()(int i,int j) const {return _data[i][j];}	//!< Accès aux données de la carte

		RGB couleur(int i,int j) const;	//!< Retourne la couleur correspondant au point (i,j), voir aussi Raster::couleur
		
		void auto_bornes();	//!< Met à jour automatiquement les bornes de la palette de couleurs en les adaptant aux valeurs minimales et maximales réelles de la carte
	
		/**
		 * \brief Importation de la carte depuis le format ArcInfo ASCII
		 *
		 * La méthode importe une partie d'un fichier raster au format ASCII ArcInfo spécifié par le paramètre fichier, et stocke la carte pour y appliquer des traitements ultérieurs. Seule la zone contenue dans les frontières spécifiée est importée.
		 * \param fichier Nom du fichier à importer
		 * \param pxmin Abscisse minimale de la zone à importer
		 * \param pymin Ordonnée minimale de la zone à importer
		 * \param pxmax Abscisse maximale de la zone à importer
		 * \param pymax Ordonnée maximale de la zone à importer
		 */
		void importe(string fichier,double pxmin,double pymin,double pxmax,double pymax) {_importe(fichier,false,pxmin,pymin,pxmax,pymax);}

		/**
		 * \brief Importation de la carte depuis le format ArcInfo ASCII
		 *
		 * La méthode importe tout le fichier raster au format ASCII ArcInfo spécifié par le paramètre fichier, et stocke la carte entièrement en mémoire pour y appliquer des traitements ultérieurs.
		 * \param fichier Nom du fichier à importer
		 */
		void importe(string fichier) {_importe(fichier,true,0,0,0,0);}
	protected:
		double **_data;	//!< Structure contenant les données
		virtual void affiche(int i,int j,ostream &out) const {out << _data[i][j];}
	private:
		/**
		 * \brief Méthode d'importation de tout ou partie d'une carte au format ArcInfo ASCII
		 *
		 * La méthode ne doit pas être utilisée directement. Elle sert uniquement d'interface commune à l'import de carte pour les fonctions RasterContinu::importe.
		 * \param fichier Nom du fichier à importer
		 * \param auto_zone Indique si la carte doit être importée dans sa totalité (valeur vraie) ou si seule la zone définie par les paramètres doit être chargée (valeur fausse)
		 * \param pxmin Abscisse minimale de la zone à importer
		 * \param pymin Ordonnée minimale de la zone à importer
		 * \param pxmax Abscisse maximale de la zone à importer
		 * \param pymax Ordonnée maximale de la zone à importer
		 */
		void _importe(string fichier,bool auto_zone,double pxmin,double pymin,double pxmax,double pymax);
};

/**
 * \class RasterDiscret
 * \brief Structure de données permettant la représentation d'une carte raster à données discrètes
 *
 * La classe, héritée de la classe Raster, permet le stockage d'une carte raster dont les données sont réparties dans des classes discrètes.
 */
class RasterDiscret:public Raster {
	public:
		/**
		 * \brief Constructeur standard
		 *
		 * Le constructeur initialise tous les champs de la classe. Ceux-ci sont obligatoires pour définir le format de la structure et notamment les fonctions d'exportation
		 * \param pclasses Nombre de classes de données
		 * \param ptaillex Nombre de cellules en abscisse
		 * \param ptailley Nombre de cellules en ordonnée
		 * \param pxmin Abscisse minimale de la carte
		 * \param pymin Ordonnée minimale de la carte
		 * \param pcellule Taille des cellules
		 */
		RasterDiscret(int pclasses,int ptaillex,int ptailley,double pxmin,double pymin,double pcellule);

		virtual ~RasterDiscret();	//!< Destructeur standard, libère les ressources associées
		int& operator()(int i,int j) const {return _data[i][j];}	//!< Accès aux données de la carte
		int classes() {return _classes;}	//!< Accès au nombre de classes de données
		RGB couleur(int i,int j) const;	//!< Retourne la couleur correspondant au point (i,j), voir aussi Raster::couleur
		RGB couleur(int num) const {return _couleurs[num];}	//!< Retourne la couleur d'indice num de la carte raster
	protected:
		int **_data;	//!< Structure contenant les données
		int _classes;	//!< Nombre de classes de données. Les classes sont représentées par les numéros 0 à _classes-1 dans _data
		RGB *_couleurs;	//!< Couleurs associées aux classes des données
		virtual void affiche(int i,int j,ostream &out) const {out << _data[i][j];}
};

#endif   // ----- #ifndef RASTER_H_INC  -----
